import { EventKeyboard, Vec3 } from 'cc';
import { ecs, EcsSystem, filter, NodeComponent } from '../../../../../../../../pkg-export/@gamex/cc-ecs';
import { DestroyComponent } from '../component/DestroyComponent';
import { PlayerComponent } from '../component/PlayerComponent';
import { InputSingleton } from '../singleton/InputSingleton';
import { KeyCode } from 'cc';
import { MeshRenderer } from 'cc';
import { math } from 'cc';
import { gameRange } from '../../../Common';
import { geometry } from 'cc';

// 键盘方向键只有这四个方向
const directType = {
    UP: Vec3.FORWARD,
    DOWN: new Vec3(0, 0, 1),
    LEFT: new Vec3(-1, 0, 0),
    RIGHT: Vec3.RIGHT
}
// 允许的键盘操作
const allowedkeys = [
    KeyCode.KEY_A,
    KeyCode.KEY_D,
    KeyCode.KEY_W,
    KeyCode.KEY_S,
    KeyCode.ARROW_UP,
    KeyCode.ARROW_DOWN,
    KeyCode.ARROW_LEFT,
    KeyCode.ARROW_RIGHT
]

export class InputSystem extends EcsSystem {
    protected filter = filter.all(PlayerComponent, NodeComponent).exclude(DestroyComponent);
    private inputManager: InputSingleton | null = null;
    private modelBounds: geometry.AABB = null;

    protected execute(): void {

        const playerEntity = this.find(this.filter);
        if (!playerEntity) return;
        if (!this.inputManager) {
            this.inputManager = this.ecs.getSingleton(InputSingleton);
        }
        if (!this.inputManager.toward.length()) return;
        const speed = 0.08;

        // playerEntity.get(NodeComponent).addPosition(this.inputManager.toward.x * speed, 0, this.inputManager.toward.z * speed);
        this.fixPlayerInBound(playerEntity.get(NodeComponent), this.inputManager.toward.x * speed, this.inputManager.toward.z * speed);
    }

    /** 限制玩家飞机范围 */
    private fixPlayerInBound(node: NodeComponent, addX: number, addZ: number) {
        if (!this.modelBounds) {
            this.modelBounds = node.entity.node.getComponentInChildren(MeshRenderer).model.modelBounds;
        }
        const modelBounds = this.modelBounds;

        const newX = math.clamp(node.x + addX, gameRange.minX + modelBounds.halfExtents.x, gameRange.maxX - modelBounds.halfExtents.x);
        const newZ = math.clamp(node.z + addZ, gameRange.minZ + modelBounds.halfExtents.z, gameRange.maxZ - modelBounds.halfExtents.z);
        node.setPosition(newX, 0, newZ);
    }

    public static onKeyDown(event: EventKeyboard) {
        if (allowedkeys.indexOf(event.keyCode) === -1) return;
        const pressKeyMap = ecs.getSingleton(InputSingleton).pressKeyMap;
        switch (event.keyCode) {
            case KeyCode.KEY_A:
            case KeyCode.ARROW_LEFT:
                pressKeyMap.set(directType.LEFT, true);
                break;
            case KeyCode.KEY_D:
            case KeyCode.ARROW_RIGHT:
                pressKeyMap.set(directType.RIGHT, true);
                break;
            case KeyCode.KEY_W:
            case KeyCode.ARROW_UP:
                pressKeyMap.set(directType.UP, true);
                break;
            case KeyCode.KEY_S:
            case KeyCode.ARROW_DOWN:
                pressKeyMap.set(directType.DOWN, true);
                break;
        }
        InputSystem.calcToward(pressKeyMap);
    }
    public static onKeyUp(event: EventKeyboard) {
        if (allowedkeys.indexOf(event.keyCode) === -1) return;
        const pressKeyMap = ecs.getSingleton(InputSingleton).pressKeyMap;
        switch (event.keyCode) {
            case KeyCode.KEY_A:
            case KeyCode.ARROW_LEFT:
                pressKeyMap.set(directType.LEFT, false);
                break;
            case KeyCode.KEY_D:
            case KeyCode.ARROW_RIGHT:
                pressKeyMap.set(directType.RIGHT, false);
                break;
            case KeyCode.KEY_W:
            case KeyCode.ARROW_UP:
                pressKeyMap.set(directType.UP, false);
                break;
            case KeyCode.KEY_S:
            case KeyCode.ARROW_DOWN:
                pressKeyMap.set(directType.DOWN, false);
                break;
        }
        InputSystem.calcToward(pressKeyMap);
    }

    /**
     * 计算玩家最终行进方向 可朝八个方行进
     * 细节：当左右同时按下时，角色静止类似《吸血鬼幸存者》的效果
     * @param pressKeyMap
     */
    private static calcToward(pressKeyMap: Map<Vec3, boolean>) {
        let x = 0;
        let z = 0;
        for (const key of pressKeyMap.keys()) {
            if (pressKeyMap.get(key)) {
                x += key.x;
                z += key.z;
            }
        }
        ecs.getSingleton(InputSingleton).toward = new Vec3(x, 0, z).normalize();
    }
}

